home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / gtksourceview-2.0 / language-specs / convert.py < prev    next >
Text File  |  2009-10-02  |  17KB  |  518 lines

  1. #!/usr/bin/env python
  2.  
  3. import xml.dom.minidom as dom
  4. import cgi
  5.  
  6. default_styles = {
  7.     'Comment' : 'def:comment',
  8.     'String' : 'def:string',
  9.     'Preprocessor' : 'def:preprocessor',
  10.     'Keyword' : 'def:keyword',
  11.     'Data Type' : 'def:type',
  12.     'Decimal' : 'def:decimal',
  13.     'Specials' : 'def:specials',
  14.     'Function' : 'def:function',
  15.     'Base-N Integer' : 'def:base-n-integer',
  16.     'Floating Point' : 'def:floating-point',
  17.     'Floating point' : 'def:floating-point',
  18.     'Others' : None,
  19.     'Other' : None,
  20.     'Others 2' : None,
  21.     'Others 3' : None,
  22. }
  23.  
  24. def escape_escape_char(ch):
  25.     if ch == '\\':
  26.         return '\\\\'
  27.     elif ch in ['@']:
  28.         return ch
  29.     raise RuntimeError("don't know how to escape '%s'" % (ch,))
  30.  
  31. def escape_regex(s):
  32.     return cgi.escape(s)
  33.  
  34. def normalize_id(id):
  35.     if id == "C#":
  36.         return "c-sharp"
  37.     elif id == ".desktop":
  38.         return "desktop"
  39.     elif id == ".ini":
  40.         return "ini"
  41.     elif id == "C++ Line Comment":
  42.         return "cpp-line-comment"
  43.     elif id == "Markup (inline)":
  44.         return "markup-inline"
  45.     elif id == "Markup (block)":
  46.         return "markup-block"
  47.     else:
  48.         return id.replace(', ', '-').replace('.', '-').replace('*', '-').replace(',', '-').replace(' ', '-').replace('/', '-').replace('#', '-').lower()
  49.  
  50. class LangFile(object):
  51.     def __init__(self, id, name, _name, section, _section, mimetypes, globs, filename):
  52.         object.__init__(self)
  53.  
  54.         assert name or _name
  55.         assert section or _section
  56.  
  57.         self.id = normalize_id(id or name or _name)
  58.         self.name = name
  59.         self._name = _name
  60.         self.section = section
  61.         self._section = _section
  62.         self.mimetypes = mimetypes
  63.         self.globs = globs
  64.         self.filename = filename
  65.         self.contexts = []
  66.         self.escape_char = None
  67.  
  68.     def set_esc_char(self, char):
  69.         self.escape_char = char
  70.  
  71.     def add_context(self, ctx):
  72.         self.contexts.append(ctx)
  73.  
  74.     def format_header(self, indent):
  75.         string = '<?xml version="1.0" encoding="UTF-8"?>\n<language id="%s"' % (self.id,)
  76.  
  77.         if self.name:
  78.             string += ' name="%s"' % (self.name,)
  79.         else:
  80.             string += ' _name="%s"' % (self._name,)
  81.  
  82.         string += ' version="2.0"'
  83.  
  84.         if self.section:
  85.             string += ' section="%s"' % (self.section,)
  86.         else:
  87.             string += ' _section="%s"' % (self._section,)
  88.  
  89.         string += '>\n'
  90.  
  91.         if self.mimetypes or self.globs:
  92.             string += indent + '<metadata>\n'
  93.             if self.mimetypes:
  94.                 string += 2*indent + '<property name="mimetypes">%s</property>\n' % (cgi.escape(self.mimetypes),)
  95.             if self.globs:
  96.                 string += 2*indent + '<property name="globs">%s</property>\n' % (cgi.escape(self.globs),)
  97.             string += indent + '</metadata>\n\n'
  98.  
  99.         return string
  100.  
  101.     def format_footer(self, indent):
  102.         return '</language>\n'
  103.  
  104.     def format_styles(self, indent):
  105.         string = indent + "<styles>\n"
  106.         styles = {}
  107.         for ctx in self.contexts:
  108.             map_to = default_styles[ctx.style_name]
  109.             styles[ctx.style] = [ctx.style_name, map_to]
  110.         for s in styles:
  111.             id = s
  112.             name, map_to = styles[s]
  113.             if map_to:
  114.                 string += indent*2 + '<style id="%s" _name="%s" map-to="%s"/>\n' % (id, name, map_to)
  115.             else:
  116.                 string += indent*2 + '<style id="%s" _name="%s"/>\n' % (id, name)
  117.         string += indent + "</styles>\n\n"
  118.         return string
  119.  
  120.     def format_contexts(self, indent):
  121.         string = indent + '<definitions>\n'
  122.  
  123.         if self.escape_char and self.escape_char != '\\':
  124.             char = escape_escape_char(self.escape_char)
  125.  
  126.             string += indent*2 + '<context id="generated-escape">\n'
  127.             string += indent*3 + '<match>%s.</match>\n' % (char,)
  128.             string += indent*2 + '</context>\n'
  129.  
  130.             string += indent*2 + '<context id="generated-line-escape">\n'
  131.             string += indent*3 + '<start>%s$</start>\n' % (char,)
  132.             string += indent*3 + '<end>^</end>\n'
  133.             string += indent*2 + '</context>\n'
  134.  
  135.         for ctx in self.contexts:
  136.             if self.escape_char:
  137.                 if self.escape_char != '\\':
  138.                     esc_ctx = 'generated-escape'
  139.                     line_esc_ctx = 'generated-line-escape'
  140.                 else:
  141.                     esc_ctx = 'def:escape'
  142.                     line_esc_ctx = 'def:line-continue'
  143.             else:
  144.                 esc_ctx = None
  145.                 line_esc_ctx = None
  146.  
  147.             string += ctx.format(indent, esc_ctx, line_esc_ctx)
  148.  
  149.         string += indent*2 + '<context id="%s">\n' % (self.id,)
  150.         string += indent*3 + '<include>\n'
  151.         for ctx in self.contexts:
  152.             string += indent*4 + '<context ref="%s"/>\n' % (ctx.id,)
  153.         string += indent*3 + '</include>\n'
  154.         string += indent*2 + '</context>\n'
  155.  
  156.         string += indent + '</definitions>\n'
  157.         return string
  158.  
  159.     def format(self, indent='  '):
  160.         string = self.format_header(indent)
  161.         string += self.format_styles(indent)
  162.         string += self.format_contexts(indent)
  163.         string += self.format_footer(indent)
  164.         return string
  165.  
  166. class Context(object):
  167.     def __init__(self, name, _name, style):
  168.         object.__init__(self)
  169.         assert (name or _name) and style
  170.         self.name = name
  171.         self._name = _name
  172.         self.style_name = style
  173.         self.style = style.replace(' ', '-').lower()
  174.         self.id = normalize_id(name or _name)
  175.         self.is_container = False
  176.  
  177.     def format(self, indent, esc_ctx, line_esc_ctx):
  178.         print "Implement me: %s.format()" % (type(self).__name__,)
  179.         return indent*2 + '<context id="%s"/>\n' % (self.id)
  180.  
  181.     def format_escape(self, indent, esc_ctx, line_esc_ctx):
  182.         string = ""
  183.         if self.is_container and esc_ctx is not None:
  184.             string += indent*3 + '<include>\n'
  185.             string += indent*4 + '<context ref="%s"/>\n' % (esc_ctx,)
  186.             string += indent*4 + '<context ref="%s"/>\n' % (line_esc_ctx,)
  187.             string += indent*3 + '</include>\n'
  188.         return string
  189.  
  190. class KeywordList(Context):
  191.     def __init__(self, name, _name, style, keywords, case_sensitive,
  192.                  match_empty_string_at_beginning,
  193.                  match_empty_string_at_end,
  194.                  beginning_regex, end_regex):
  195.         Context.__init__(self, name, _name, style)
  196.         self.keywords = keywords
  197.         self.case_sensitive = case_sensitive # ???
  198.         self.match_empty_string_at_beginning = match_empty_string_at_beginning
  199.         self.match_empty_string_at_end = match_empty_string_at_end
  200.         self.beginning_regex = beginning_regex
  201.         self.end_regex = end_regex
  202.  
  203.     def format(self, indent, esc_ctx, line_esc_ctx):
  204.         string = indent*2 + '<context id="%s" style-ref="%s">\n' % (self.id, self.style)
  205.  
  206.         if self.beginning_regex:
  207.             string += indent*3 + '<prefix>%s</prefix>\n' % (escape_regex(self.beginning_regex),)
  208.         elif not self.match_empty_string_at_beginning:
  209.             string += indent*3 + '<prefix></prefix>\n'
  210.  
  211.         if self.end_regex:
  212.             string += indent*3 + '<suffix>%s</suffix>\n' % (escape_regex(self.end_regex),)
  213.         elif not self.match_empty_string_at_end:
  214.             string += indent*3 + '<suffix></suffix>\n'
  215.  
  216.         for kw in self.keywords:
  217.             string += indent*3 + '<keyword>%s</keyword>\n' % (escape_regex(kw),)
  218.  
  219.         string += self.format_escape(indent, esc_ctx, line_esc_ctx)
  220.         string += indent*2 + '</context>\n'
  221.         return string
  222.  
  223. class PatternItem(Context):
  224.     def __init__(self, name, _name, style, pattern):
  225.         Context.__init__(self, name, _name, style)
  226.         assert pattern
  227.         self.pattern = pattern
  228.  
  229.     def format(self, indent, esc_ctx, line_esc_ctx):
  230.         string = indent*2 + '<context id="%s" style-ref="%s">\n' % (self.id, self.style)
  231.         string += indent*3 + '<match>%s</match>\n' % (escape_regex(self.pattern),)
  232.         string += self.format_escape(indent, esc_ctx, line_esc_ctx)
  233.         string += indent*2 + '</context>\n'
  234.         return string
  235.  
  236. class LineComment(Context):
  237.     def __init__(self, name, _name, style, start):
  238.         Context.__init__(self, name, _name, style)
  239.         assert start
  240.         self.start = start
  241.         self.is_container = True
  242.  
  243.     def format(self, indent, esc_ctx, line_esc_ctx):
  244.         string = indent*2 + '<context id="%s" style-ref="%s" end-at-line-end="true">\n' % (self.id, self.style)
  245.         string += indent*3 + '<start>%s</start>\n' % (escape_regex(self.start),)
  246.         string += self.format_escape(indent, esc_ctx, line_esc_ctx)
  247.         string += indent*2 + '</context>\n'
  248.         return string
  249.  
  250. class BlockComment(Context):
  251.     def __init__(self, name, _name, style, start, end):
  252.         Context.__init__(self, name, _name, style)
  253.         assert start and end
  254.         self.start = start
  255.         self.end = end
  256.         self.is_container = True
  257.  
  258.     def format(self, indent, esc_ctx, line_esc_ctx):
  259.         string = indent*2 + '<context id="%s" style-ref="%s">\n' % (self.id, self.style)
  260.         string += indent*3 + '<start>%s</start>\n' % (escape_regex(self.start),)
  261.         string += indent*3 + '<end>%s</end>\n' % (escape_regex(self.end),)
  262.         string += self.format_escape(indent, esc_ctx, line_esc_ctx)
  263.         string += indent*2 + '</context>\n'
  264.         return string
  265.  
  266. class String(Context):
  267.     def __init__(self, name, _name, style, start, end, end_at_line_end):
  268.         Context.__init__(self, name, _name, style)
  269.         assert start and end
  270.         self.start = start
  271.         if end and end.endswith("\\n"):
  272.             end = end[:-2]
  273.             end_at_line_end = True
  274.         self.end = end
  275.         self.end_at_line_end = end_at_line_end
  276.         self.is_container = True
  277.  
  278.     def format(self, indent, esc_ctx, line_esc_ctx):
  279.         string = indent*2 + '<context id="%s" style-ref="%s"' % (self.id, self.style)
  280.         if self.end_at_line_end:
  281.             string += ' end-at-line-end="true"'
  282.         string += '>\n'
  283.  
  284.         if self.start:
  285.             string += indent*3 + '<start>%s</start>\n' % (escape_regex(self.start),)
  286.         if self.end:
  287.             string += indent*3 + '<end>%s</end>\n' % (escape_regex(self.end),)
  288.  
  289.         string += self.format_escape(indent, esc_ctx, line_esc_ctx)
  290.         string += indent*2 + '</context>\n'
  291.         return string
  292.  
  293. class SyntaxItem(Context):
  294.     def __init__(self, name, _name, style, start, end):
  295.         Context.__init__(self, name, _name, style)
  296.         assert start and end
  297.         self.start = start
  298.         self.end = end
  299.         self.end_at_line_end = False
  300.         if end and end.endswith("\\n"):
  301.             self.end = end[:-2]
  302.             self.end_at_line_end = True
  303.         self.is_container = True
  304.  
  305.     def format(self, indent, esc_ctx, line_esc_ctx):
  306.         string = indent*2 + '<context id="%s" style-ref="%s"' % (self.id, self.style)
  307.         if self.end_at_line_end:
  308.             string += ' end-at-line-end="true"'
  309.         string += '>\n'
  310.  
  311.         if self.start:
  312.             string += indent*3 + '<start>%s</start>\n' % (escape_regex(self.start),)
  313.         if self.end:
  314.             string += indent*3 + '<end>%s</end>\n' % (escape_regex(self.end),)
  315.  
  316.         string += self.format_escape(indent, esc_ctx, line_esc_ctx)
  317.         string += indent*2 + '</context>\n'
  318.         return string
  319.  
  320. def first_child(node):
  321.     child = node.firstChild
  322.     while child is not None and child.nodeType != dom.Node.ELEMENT_NODE:
  323.         child = child.nextSibling
  324.     return child
  325. def next_sibling(node):
  326.     next = node.nextSibling
  327.     while next is not None and next.nodeType != dom.Node.ELEMENT_NODE:
  328.         next = next.nextSibling
  329.     return next
  330.  
  331. def parseLineComment(cur, name, _name, style):
  332.     child = first_child(cur)
  333.     assert child is not None and child.tagName == "start-regex"
  334.     return LineComment(name, _name, style, child.firstChild.nodeValue)
  335.  
  336. def parseBlockComment(cur, name, _name, style):
  337.     start_regex = None
  338.     end_regex = None
  339.     child = first_child(cur)
  340.  
  341.     while child is not None:
  342.         if child.tagName == "start-regex":
  343.             start_regex = child.firstChild.nodeValue
  344.         elif child.tagName == "end-regex":
  345.             end_regex = child.firstChild.nodeValue
  346.         child = next_sibling(child)
  347.  
  348.     assert start_regex is not None
  349.     assert end_regex is not None
  350.  
  351.     return BlockComment(name, _name, style, start_regex, end_regex)
  352.  
  353. def parseString(cur, name, _name, style):
  354.     start_regex = None
  355.     end_regex = None
  356.     end_at_line_end = True
  357.  
  358.     prop = cur.getAttribute("end-at-line-end")
  359.     if prop:
  360.         if prop in ["TRUE", "1"]:
  361.             end_at_line_end = True
  362.         else:
  363.             end_at_line_end = False
  364.  
  365.     child = first_child(cur)
  366.  
  367.     while child is not None:
  368.         if child.tagName == "start-regex":
  369.             start_regex = child.firstChild.nodeValue
  370.         elif child.tagName == "end-regex":
  371.             end_regex = child.firstChild.nodeValue
  372.         child = next_sibling(child)
  373.  
  374.     assert start_regex is not None
  375.     assert end_regex is not None
  376.  
  377.     return String(name, _name, style, start_regex, end_regex, end_at_line_end)
  378.  
  379. def parseKeywordList(cur, name, _name, style):
  380.     case_sensitive = True
  381.     match_empty_string_at_beginning = True
  382.     match_empty_string_at_end = True
  383.     beginning_regex = None
  384.     end_regex = None
  385.     keywords = []
  386.  
  387.     prop = cur.getAttribute("case-sensitive")
  388.     if prop:
  389.         if prop in ["TRUE", "1"]:
  390.             case_sensitive = True
  391.         else:
  392.             case_sensitive = False
  393.  
  394.     prop = cur.getAttribute("match-empty-string-at-beginning")
  395.     if prop:
  396.         if prop in ["TRUE", "1"]:
  397.             match_empty_string_at_beginning = True
  398.         else:
  399.             match_empty_string_at_beginning = False
  400.  
  401.     prop = cur.getAttribute("match-empty-string-at-end")
  402.     if prop:
  403.         if prop in ["TRUE", "1"]:
  404.             match_empty_string_at_end = True
  405.         else:
  406.             match_empty_string_at_end = False
  407.  
  408.     prop = cur.getAttribute("beginning-regex")
  409.     if prop:
  410.         beginning_regex = prop
  411.  
  412.     prop = cur.getAttribute("end-regex")
  413.     if prop:
  414.         end_regex = prop
  415.  
  416.     child = first_child(cur)
  417.  
  418.     while child is not None:
  419.         if child.tagName == "keyword":
  420.             keywords.append(child.firstChild.nodeValue)
  421.         child = next_sibling(child)
  422.  
  423.     assert keywords
  424.  
  425.     return KeywordList(name, _name, style, keywords, case_sensitive,
  426.                        match_empty_string_at_beginning,
  427.                        match_empty_string_at_end,
  428.                        beginning_regex, end_regex)
  429.  
  430. def parsePatternItem(cur, name, _name, style):
  431.     child = first_child(cur)
  432.     assert child is not None and child.tagName == "regex"
  433.     return PatternItem(name, _name, style, child.firstChild.nodeValue)
  434.  
  435. def parseSyntaxItem(cur, name, _name, style):
  436.     start_regex = None
  437.     end_regex = None
  438.  
  439.     child = first_child(cur)
  440.  
  441.     while child is not None:
  442.         if child.tagName == "start-regex":
  443.             start_regex = child.firstChild.nodeValue
  444.         elif child.tagName == "end-regex":
  445.             end_regex = child.firstChild.nodeValue
  446.         child = next_sibling(child)
  447.  
  448.     assert start_regex is not None
  449.     assert end_regex is not None
  450.  
  451.     return SyntaxItem(name, _name, style, start_regex, end_regex)
  452.  
  453. def parseTag(cur):
  454.     _name = None
  455.     name = None
  456.  
  457.     _name = cur.getAttribute("_name")
  458.     name = cur.getAttribute("name")
  459.     assert name or _name
  460.     style = cur.getAttribute("style") or "Normal"
  461.  
  462.     if cur.tagName == "line-comment":
  463.         ctx = parseLineComment(cur, name, _name, style)
  464.     elif cur.tagName == "block-comment":
  465.         ctx = parseBlockComment(cur, name, _name, style)
  466.     elif cur.tagName == "string":
  467.         ctx = parseString(cur, name, _name, style)
  468.     elif cur.tagName == "keyword-list":
  469.         ctx = parseKeywordList(cur, name, _name, style)
  470.     elif cur.tagName == "pattern-item":
  471.         ctx = parsePatternItem(cur, name, _name, style)
  472.     elif cur.tagName == "syntax-item":
  473.         ctx = parseSyntaxItem(cur, name, _name, style)
  474.     else:
  475.         print "Unknown tag: %s" % (cur.tagName,)
  476.         ctx = None
  477.  
  478.     return ctx
  479.  
  480. def parse_file(filename):
  481.     doc = dom.parse(filename)
  482.     node = doc.documentElement
  483.     contexts = []
  484.     esc_char = None
  485.  
  486.     assert node.tagName == "language"
  487.  
  488.     lang_file = LangFile(node.getAttribute("id"),
  489.                          node.getAttribute("name"),
  490.                          node.getAttribute("_name"),
  491.                          node.getAttribute("section"),
  492.                          node.getAttribute("_section"),
  493.                          node.getAttribute("mimetypes"),
  494.                          node.getAttribute("globs"),
  495.                          filename)
  496.  
  497.     node = first_child(node)
  498.     assert node is not None
  499.  
  500.     while node is not None:
  501.         if node.tagName == "escape-char":
  502.             lang_file.set_esc_char(node.firstChild.nodeValue)
  503.         else:
  504.             lang_file.add_context(parseTag(node))
  505.         node = next_sibling(node)
  506.  
  507.     return lang_file
  508.  
  509. if __name__ == '__main__':
  510.     import sys
  511.  
  512.     if not sys.argv[1:]:
  513.         print "usage: %s LANG_FILE" % (sys.argv[0])
  514.         sys.exit(1)
  515.  
  516.     lang_file = parse_file(sys.argv[1])
  517.     sys.stdout.write(lang_file.format())
  518.